﻿using System;
using System.IO;
using System.IO.Compression;
using System.Linq.Expressions;
using Serialize.Linq.Extensions;
using Serialize.Linq.Internals;
using Serialize.Linq.Nodes;
using Serialize.Linq.Serializers;

namespace ProLinq.Wcf.Linq.Expressions.Serialization
{
	internal class ZippedJsonExpressionSerializer : IExpressionSerializer
	{
		static ZippedJsonExpressionSerializer()
		{
			// TODO: remove when fixed in Serialize.Linq
			// Decimal? deserialization fix
			ValueConverter.AddCustomConverter(typeof(Nullable<Decimal>), p =>
			{
				var d = Convert.ToDecimal(p);
				return (Decimal?)d;
			});
		}

		#region IExpressionSerializer Members

		public Byte[] Serialize(Expression expression)
		{
			var expressionJson = expression.ToJson();
			using (var mem = new MemoryStream())
			{
				using (var zip = new GZipStream(mem, CompressionLevel.Optimal))
				{
					using (var textWriter = new StreamWriter(zip))
					{
						textWriter.Write(expressionJson);
					}
				}

				return mem.ToArray();
			}
		}

		public Expression Deserialize(Byte[] bytes)
		{
			String expressionJson;
			using (var mem = new MemoryStream(bytes))
			{
				using (var zip = new GZipStream(mem, CompressionMode.Decompress))
				{
					using (var textReader = new StreamReader(zip))
					{
						expressionJson = textReader.ReadToEnd();
					}
				}
			}

			var serializer = new JsonSerializer();

			var node = serializer.Deserialize<ExpressionNode>(expressionJson);
			return node.ToExpression();
		}

		#endregion
	}
}